<template>
  <div v-show="opened" ref="elRef" tabindex="1" id="contextmenu" class="contextmenu" :style="Root.style" @contextmenu.prevent @blur="Root.close">
    <div class="area">
      <slot/>
    </div>
  </div>
</template>
<script setup lang="ts">
const mouse = useMouse()
const elRef = ref<HTMLDivElement>()
const opened = defineModel("open", {
  default: false
})
const Root = (() => {
  const setWatcher = () => {
    watch(() => opened.value, open)
  };
  const open = () => {
    s.x = mouse.x.value
    s.y = mouse.y.value
    nextTick(() => {
      elRef.value?.focus()
    })
  };
  const close = () => {
    opened.value = false
  };
  const s = reactive({
    x: 0,
    y: 0,
    maxHeight: 0,
    maxWidth: 0,
    style: computed(() => {
      const dom = document.getElementById('contextmenu')
      const height = dom?.offsetHeight ?? 0;
      const width = dom?.offsetWidth ?? 0;
      const maxHeight = s.maxHeight || window.innerHeight - height;
      const maxWidth = s.maxWidth || window.innerWidth - width;
      height && (s.maxHeight = maxHeight)
      width && (s.maxWidth = maxWidth)
      const obj = {
        top: s.y < maxHeight && s.y + "px",
        bottom: s.y >= maxHeight && window.innerHeight - s.y + "px",
        left: s.x < maxWidth && s.x + "px",
        right: s.x >= maxWidth && window.innerWidth - s.x + "px"
      }
      Object.keys(obj).forEach(key => {
        !obj[key] && delete obj[key]
      })
      return obj
    }),
    open,
    close
  })
  setWatcher()
  return s
})()
defineExpose({
  open: Root.open,
  close: Root.close,
})
</script>
<style scoped>
.contextmenu {
  border-radius: 0.5rem;
  box-shadow: 1px 8px 16px rgba(0, 0, 0, 0.31);
  position: fixed;
  z-index: 10000;
  width: 18rem;
  background: #ffffff;

  .area {
    margin-top: 0.5rem;
    user-select: none;

    * {
      width: 100%;
      padding-left: 1.3rem;
      font-size: 13px;
    }

    *:hover {
      background: #f1f1f1;
    }

  }
}
</style>